import 'package:flutter/material.dart';
import 'dart:async';

class PasswordValidator extends StatelessWidget {
  final StreamController<String> _inputController = StreamController<String>();

  PasswordValidator({super.key});

  final _padding = 8.0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('密码强度校验'),
      ),
      body: Center(
        child: Padding(
          padding: EdgeInsets.fromLTRB(_padding, 0.0, _padding, 0.0),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              TextField(
                keyboardType: TextInputType.visiblePassword,
                onChanged: (text) {
                  _inputController.add(text);
                },
                decoration: const InputDecoration(labelText: '请输入密码'),
              ),
              const SizedBox(height: 20),
              StreamBuilder<String>(
                stream: _inputController.stream,
                initialData: '',
                builder: (context, snapshot) {
                  final passwordStrength = calculateStrength(snapshot.data!);
                  return PasswordStrengthIndicator(
                      passwordStrength: passwordStrength, lineHeight: 4.0);
                },
              ),
            ],
          ),
        ),
      ),
    );
  }

  PasswordStrength calculateStrength(String password) {
    if (password.length >= 8) {
      bool hasDigit = false;
      bool hasLetter = false;
      bool hasSpecial = false;

      for (var char in password.split('')) {
        if (RegExp(r'[0-9]').hasMatch(char)) {
          hasDigit = true;
        } else if (RegExp(r'[A-Za-z]').hasMatch(char)) {
          hasLetter = true;
        } else {
          hasSpecial = true;
        }
      }

      if (hasDigit && hasLetter && hasSpecial) {
        return PasswordStrength.strong;
      } else if ((hasDigit && hasLetter) ||
          (hasDigit && hasSpecial) ||
          (hasLetter && hasSpecial)) {
        return PasswordStrength.medium;
      }
    }
    return PasswordStrength.weak;
  }
}

enum PasswordStrength { strong, medium, weak }

class PasswordStrengthIndicator extends StatelessWidget {
  final PasswordStrength passwordStrength;
  final double lineHeight;
  const PasswordStrengthIndicator(
      {super.key, required this.passwordStrength, required this.lineHeight});

  final _strengthGapWidth = 8.0;
  @override
  Widget build(BuildContext context) {
    var passwordIndicator =
        PasswordIndicator(passwordStrength: passwordStrength);
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Flexible(
          flex: 1,
          child: Container(
            height: lineHeight,
            color: passwordIndicator.lineColors[0],
          ),
        ),
        SizedBox(width: _strengthGapWidth),
        Flexible(
          flex: 1,
          child: Container(
            height: lineHeight,
            color: passwordIndicator.lineColors[1],
          ),
        ),
        SizedBox(width: _strengthGapWidth),
        Flexible(
          flex: 1,
          child: Container(
            height: lineHeight,
            color: passwordIndicator.lineColors[2],
          ),
        ),
        SizedBox(width: _strengthGapWidth),
        Text(
          passwordIndicator.strengthText,
          style: TextStyle(
            fontWeight: FontWeight.bold,
            color: passwordIndicator.strengthTextColor,
          ),
        ),
      ],
    );
  }
}

class PasswordIndicator {
  final PasswordStrength passwordStrength;
  late List<Color> _lineColors;
  late String _strengthText;
  late Color _strengthTextColor;

  PasswordIndicator({required this.passwordStrength}) {
    switch (passwordStrength) {
      case PasswordStrength.weak:
        _lineColors = const [
          Color(0xFFCCCCCC),
          Color(0xFFCCCCCC),
          Color(0xFFCCCCCC)
        ];
        _strengthText = '弱';
        _strengthTextColor = Colors.red;
        break;
      case PasswordStrength.medium:
        _lineColors = const [
          Color(0xFF00A52B),
          Color(0xFF00A52B),
          Color(0xFFCCCCCC)
        ];
        _strengthText = '中等';
        _strengthTextColor = Colors.orange;
        break;
      default:
        _lineColors = const [
          Color(0xFF00A52B),
          Color(0xFF00A52B),
          Color(0xFF00A52B)
        ];
        _strengthText = '强';
        _strengthTextColor = const Color(0xFF00A52B);
        break;
    }
  }

  get lineColors => _lineColors;
  get strengthText => _strengthText;
  get strengthTextColor => _strengthTextColor;
}
